package com.huijie.core.util.importexcel;
/**
 * authour:lxy
 */

import org.apache.commons.lang.StringUtils;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.compile;


public class ExcelImportUtil {

    private final static String XLS = "xls";
    private final static String XLSX = "xlsx";
    private final static String FALG_F = "F";

    public static ExcelBean upload(String[] str, String[] type, String[] checknull, int[] length, int[] prmKey, MultipartFile file) throws Exception {
        ExcelBean excelBean = new ExcelBean();
        List<String> errorMessage = new ArrayList<>();
        try {
            //此时的Workbook应该是从 客户端浏览器上传过来的 uploadFile了,其实跟读取本地磁盘的一个样
            Workbook workbook = getWorkBook(file);
            //向controller中传递错误信息或者数据集用于数据库插入
            List<String[]> list = new ArrayList<>();
            //将所有的错误信息传递给前台
            //验证excel中的数据是否有重复的
            List<String[]> check = new ArrayList<>();
            List<Cell[]> listCell = new ArrayList<>();
            long start1 = System.currentTimeMillis();
            if (workbook != null) {
                //获得当前sheet工作表
                Sheet sheet = workbook.getSheetAt(0);
                if (sheet == null) {
                    errorMessage.add("模板不能为空");
                    excelBean.setResultList(errorMessage);
                    return excelBean;
                }
                //验证标题列是否为空
                Row rowHeader = sheet.getRow(0);
                if (rowHeader == null) {
                    errorMessage.add("第一页模板不能为空，请重新选择模板");
                    excelBean.setResultList(errorMessage);
                    return excelBean;
                }
                rowHeader.getPhysicalNumberOfCells();
                rowHeader.getLastCellNum();
                //验证抬头列是否与标准模板列数一致
//	            if (rowHeader.getLastCellNum()>str.length) {
////	            	errorMessage.add("模板标题为"+rowHeader.getLastCellNum()+"列大于标准模板列数，标准模板为："+str);
//	            	errorMessage.add("模板不对，请重新下载模板");
//	            	excelBean.setResultList(errorMessage);
//	            	return excelBean;
//				}else
                if (rowHeader.getLastCellNum() < str.length) {
//					errorMessage.add("模板标题为"+rowHeader.getLastCellNum()+"列小于标准模板列数，标准模板为："+str);
                    errorMessage.add("模板不对，请重新下载模板");
                    excelBean.setResultList(errorMessage);
                    return excelBean;
                }
                //验证表头
                for (int i = 0; i < str.length; i++) {
//	            	str[i]=str[i].replace(" ", "");
                    if (rowHeader.getCell(i).toString() == null) {
//	            		errorMessage.add("模板第"+(i+1)+"列为空，请下载标准模板<br/>");
                        errorMessage.add("模板不对，请重新下载模板");
                        excelBean.setResultList(errorMessage);
                        return excelBean;
                    }
                    if (!(str[i].equals(rowHeader.getCell(i).toString()))) {
//	            		excelBean.setResult("第"+sheetNum+"页模板不对");
//	            		errorMessage.add("模板第"+(i+1)+"列不对，请下载标准模板<br/>");
                        errorMessage.add("模板不对，请重新下载模板");
                        excelBean.setResultList(errorMessage);
                        return excelBean;
//						return excelBean;
                    }
                }
                //获得当前行的列数
                int lastCellNum = str.length;
                //获得当前sheet的开始行
                int firstRowNum = sheet.getFirstRowNum();
                //获得当前sheet的结束行
                int lastRowNum = sheet.getLastRowNum();
                //获取excel中实际数据
                DataFormatter formatter = new DataFormatter();
                //循环每一行
                for (int rowNum = firstRowNum + 1; rowNum <= lastRowNum; rowNum++) {
                    //获得当前行
                    Row row = sheet.getRow(rowNum);
                    if (row == null) {
                        continue;
                    }
                    //获得当前行的开始列
                    int firstCellNum = row.getFirstCellNum();

                    String[] cells = new String[str.length];
                    String[] prmKeys = null;
                    if (null == prmKey) {
                        prmKeys = new String[0];
                    } else {
                        prmKeys = new String[prmKey.length];
                    }
                    //循环当前列
                    for (int cellNum = firstCellNum; cellNum < lastCellNum; cellNum++) {
                        String msg = "第1页第" + (rowNum + 1) + "行第" + (cellNum + 1) + "列数据";
                        //判断字段是否为空
                        boolean bools = isnull(String.valueOf(row.getCell(cellNum)), checknull[cellNum]);
                        if (!bools) {
                            errorMessage.add(msg + "不能为空<br/>");
                        }
                        //长度不能小于多少
                        if ("NS".equals(checknull[cellNum])) {
                            if (("".equals(formatter.formatCellValue(row.getCell(cellNum))))) {
                                errorMessage.add(msg + "不能为空<br/>");
                            } else {
                                //如果类型为字符串类型则判断类型的长度
                                if ("STR".equals(type[cellNum])) {
                                    boolean bool = length(formatter.formatCellValue(row.getCell(cellNum)).toString().length(), length[cellNum]);

                                    if (formatter.formatCellValue(row.getCell(cellNum)).toString().length() < length[cellNum]) {
                                        errorMessage.add(msg + "长度不能小于" + length[cellNum] + "<br/>");
                                    }
                                }
                            }
                        }
                        //不允许为空，长度不可变
                        if ("FF".equals(checknull[cellNum])) {
                            if (("".equals(formatter.formatCellValue(row.getCell(cellNum))))) {
                                errorMessage.add(msg + "不能为空");
                            } else {
                                //如果类型为字符串类型则判断类型的长度
                                if ("STR".equals(type[cellNum])) {
                                    boolean bool = length(formatter.formatCellValue(row.getCell(cellNum)).toString().length(), length[cellNum]);
                                    if (!bool) {
                                        errorMessage.add(msg + "长度应为" + length[cellNum] + "<br/>");
                                    }
                                }
                            }
                        } else if ("FT".equals(checknull[cellNum])) {
                            if (("".equals(formatter.formatCellValue(row.getCell(cellNum))))) {
                                errorMessage.add(msg + "不能为空<br/>");
                            } else {
                                //如果类型为字符串类型则判断类型的长度
                                if ("STR".equals(type[cellNum])) {
                                    if (formatter.formatCellValue(row.getCell(cellNum)).toString().length() > length[cellNum]) {
                                        errorMessage.add(msg + "长度超过应有长度" + length[cellNum] + "<br/>");
                                    }
                                }
                            }
                        } else if ("TT".equals(checknull[cellNum])) {
                            if (("".equals(formatter.formatCellValue(row.getCell(cellNum))))) {
                            } else {
                                //如果类型为字符串类型则判断类型的长度
                                if ("STR".equals(type[cellNum]) && (formatter.formatCellValue(row.getCell(cellNum)).toString().length() > length[cellNum])) {
                                    errorMessage.add(msg + "长度超过应有长度" + length[cellNum] + "<br/>");
                                }
                            }
                        } else if ("TF".equals(checknull[cellNum])) {
                            if (("".equals(formatter.formatCellValue(row.getCell(cellNum))))) {
                            } else {
                                //如果类型为字符串类型则判断类型的长度
                                if ("STR".equals(type[cellNum]) && (!length(formatter.formatCellValue(row.getCell(cellNum)).toString().length(), length[cellNum]))) {
                                    errorMessage.add(msg + "长度应为" + length[cellNum] + "<br/>");
                                }
                            }
                        }
                        Object inputValue = null;
                        //因为excel导入的数据都是double类型的所以在判断整型的时候需要把0给去掉
                        if (row.getCell(cellNum) != null && row.getCell(cellNum).getCellType() == Cell.CELL_TYPE_NUMERIC) {

                            long longVal = Math.round(row.getCell(cellNum).getNumericCellValue());

                            if (Double.parseDouble(longVal + ".0") == row.getCell(cellNum).getNumericCellValue()) {
                                inputValue = longVal;
                            } else {
                                inputValue = row.getCell(cellNum).getNumericCellValue();
                            }

                        }
                        if (inputValue == null) {
                            inputValue = formatter.formatCellValue(row.getCell(cellNum));
                        }
                        //判断是否为数字类型
                        if ("NU".equals(type[cellNum])) {
                            boolean spfml = spfml(inputValue.toString().replaceFirst(",", ""));
                            if (!spfml) {
                                errorMessage.add(msg + "应该为数字<br/>");
                            }
                        }
                        //判断是否为整型
                        if ("INT".equals(type[cellNum])) {
                            boolean spfml = isInteger(inputValue.toString().replace(" ", ""));
                            if (!spfml) {
                                errorMessage.add(msg + "应该整数<br/>");
                            }
                        }
                        //判断是否为浮点型
                        if ("DOUB".equals(type[cellNum])) {
                            boolean spfml = isDouble(formatter.formatCellValue(row.getCell(cellNum)));
                            if (!spfml) {
                                errorMessage.add(msg + "浮点型<br/>");
                            }
                        }
                        //判断是否为日期类型
                        if ("DT".equals(type[cellNum])) {
                            boolean spfml = converDate(row.getCell(cellNum));
                            if (!spfml) {
                                errorMessage.add(msg + "应该为日期<br/>");
                            } else {
                                //今天
                                cells[cellNum] = MyexcelUtil.formatCell3(row.getCell(cellNum));
                            }
                        } else {
                            //今天
                            Cell cell = row.getCell(cellNum);
                            cells[cellNum] = getCellValue(cell);
                        }
                        if (null != prmKey) {
                            for (int i = 0; i < prmKey.length; i++) {
                                if (cellNum == prmKey[i]) {
                                    prmKeys[i] = formatter.formatCellValue(row.getCell(cellNum)).toString();
                                }
                            }
                        }
                    }
                    list.add(cells);
                    //用于校验excel中的数据有没有重复
                    check.add(prmKeys);
                }
                workbook.close();
            } else {
                errorMessage.add("模板不正确,请重新选择");
                excelBean.setResultList(errorMessage);
                return excelBean;
            }
//		System.out.println("字段校验本次遍历消耗了:" + (System.currentTimeMillis() - start1)  
//                + "毫秒!");
            //excel传入的数据进行验重，而后进行与数据库中数据验重
            long start2 = System.currentTimeMillis();
            if ((null == excelBean.getResultList()) || excelBean.getResultList().size() == 0) {
                //用于校验excel中是否有重复数据
                if (prmKey != null) {
                    Set<String> set = new HashSet<>();
                    Set<String> set1 = new HashSet<>();
                    List<String[]> checkLists = new ArrayList<String[]>();
                    for (int i = 0; i < check.size(); i++) {
                        //当前行主键数据即i行
                        String[] prmkeyRow = check.get(i);
                        //
                        StringBuilder sb = new StringBuilder();
                        for (String s : prmkeyRow) {
                            sb.append(s);
                        }
                        String result = sb.toString();
                        //
                        if (set.contains(result)) {
                            if (!set1.contains(result)) {
                                String[] error = new String[3];
                                error[0] = result;
                                error[1] = "";
                                checkLists.add(error);
//	                    System.out.println("重复的数字"+"第"+i+"行的数据"+result);
                                set1.add(result);
                            }
                        } else {
                            set.add(result);
                        }
                    }
                    for (int i = 0; i < check.size(); i++) {
                        //当前行主键数据即i行
                        String[] prmkeyRow = check.get(i);
                        //
                        StringBuilder sb = new StringBuilder();
                        for (String s : prmkeyRow) {
                            sb.append(s);
                        }
                        String result = sb.toString();
                        for (int j = 0; j < checkLists.size(); j++) {
                            if (result.equals(checkLists.get(j)[0])) {
                                checkLists.get(j)[1] += "第" + (i + 2) + "行数据与";
                            }
                        }
                        //
                    }
                    for (int i = 0; i < checkLists.size(); i++) {
                        errorMessage.add(checkLists.get(i)[1].substring(0, checkLists.get(i)[1].length() - 1) + "重复<br/>");
                    }
                }
                //将最终的excel传入控制台
                excelBean.setList(list);
                excelBean.setResultList(errorMessage);
                excelBean.setListAll(check);
            }
//        System.out.println("excel验重本次遍历消耗了:" + (System.currentTimeMillis() - start2)  
//                + "毫秒!");
            return excelBean;
        } catch (Exception e) {
            // TODO Auto-generated catch block
//			errorMessage.clear();
            errorMessage.add("导入失败PROG-E");
            excelBean.setResultList(errorMessage);
            e.printStackTrace();
            return excelBean;
        }
    }

    /**
     * 判断字段是否允许为空
     *
     * @param cell
     * @param bool
     * @return
     */
    public static boolean isnull(String cell, String bool) {
        //如果不允许为空并且excel传递过来的数据为空
        if (FALG_F.equals(bool) && ("".equals(cell))) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 判断字段长度是否合法
     *
     * @param spfml
     * @param length
     * @return
     */
    public static boolean length(int spfml, int length) {
        if (length == 0) {
            return true;
        } else {
            if (spfml == length) {
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * 判断字段是否为数字类型
     *
     * @param spfml
     * @return
     */
    public static boolean spfml(String spfml) {
        try {
            if (StringUtils.isNotEmpty(spfml)) {
                spfml = spfml.trim();
            } else {
                return true;
            }
            new BigDecimal(spfml);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 判断字段是否为日期类型
     *
     * @param cell
     * @return
     */
    public static boolean converDate(Cell cell) {
        try {
            Date date = cell.getDateCellValue();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static String getCellValue(Cell cell) {
        String cellValue = "";
        if (cell == null) {
            return cellValue;
        }
        //把数字当成String来读，避免出现1读成1.0的情况
        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            cell.setCellType(Cell.CELL_TYPE_STRING);
        }
        //判断数据的类型  
        switch (cell.getCellType()) {
            //数字
            case Cell.CELL_TYPE_NUMERIC:
                cellValue = String.valueOf(cell.getNumericCellValue());
                break;
            //字符串
            case Cell.CELL_TYPE_STRING:
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            //Boolean
            case Cell.CELL_TYPE_BOOLEAN:
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            //公式
            case Cell.CELL_TYPE_FORMULA:
                cellValue = String.valueOf(cell.getCellFormula());
                break;
            //空值
            case Cell.CELL_TYPE_BLANK:
                cellValue = "";
                break;
            //故障
            case Cell.CELL_TYPE_ERROR:
                cellValue = "非法字符";
                break;
            default:
                cellValue = "未知类型";
                break;
        }
        return cellValue;
    }

    /**
     * 判断是文件是属于xls类型还是xlsx类型
     *
     * @param file
     * @return
     * @throws EncryptedDocumentException
     * @throws InvalidFormatException
     */
    public static Workbook getWorkBook(MultipartFile file) throws EncryptedDocumentException, InvalidFormatException {
        //获得文件名
        String fileName = file.getOriginalFilename();
        //创建Workbook工作薄对象，表示整个excel
        Workbook workbook = null;
        try {
            //获取excel文件的io流
            InputStream is = file.getInputStream();
            //根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象  
            if (fileName.endsWith(XLS)) {
                //2003
                workbook = new HSSFWorkbook(is);
            } else if (fileName.endsWith(XLSX)) {
                //2007
                workbook = WorkbookFactory.create(is);
            }
        } catch (IOException e) {
        }
        return workbook;

    }

    /**
     * 判断是否为整数
     *
     * @param str 传入的字符串
     * @return 是整数返回true, 否则返回false
     */
    public static boolean isInteger(String str) {
        Pattern pattern = compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(str).matches();
    }

    /**
     * 判断是否为浮点数，包括double和float
     *
     * @param str 传入的字符串
     * @return 是浮点数返回true, 否则返回false
     */
    public static boolean isDouble(String str) {
        Pattern pattern = compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(str).matches();
    }
}
